package com.springboot.demo.common.interceptor;

import java.io.BufferedReader;
import java.lang.reflect.Method;
import java.util.Enumeration;
import java.util.HashMap;
import java.util.Map;
import java.util.TreeMap;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.core.env.Environment;
import org.springframework.web.method.HandlerMethod;
import org.springframework.web.servlet.HandlerInterceptor;
import org.springframework.web.servlet.ModelAndView;

import com.alibaba.fastjson.JSONObject;
import com.springboot.demo.common.config.Constant;
import com.springboot.demo.common.enums.ErrorCode;
import com.springboot.demo.common.exception.BusinessException;
import com.springboot.demo.common.utils.MD5Utils;

import lombok.extern.slf4j.Slf4j;

/**
 * @ClassName:MyInterceptor.java
 * @Package com.springboot.demo.common.interceptor
 * @Description:自定义拦截器
 * @Author JuoChiu
 * @Date  2018年3月1日下午3:11:10
 * @Version
 */
@Slf4j
public class MyInterceptor implements HandlerInterceptor {

    private Logger log = LoggerFactory.getLogger(this.getClass());

    // @Autowired
    // private ChbUserService chbUserService; // todo 签名验证
    
    @Autowired
	private HttpServletRequest request;
    
    @Autowired
	private Environment env;

    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
        boolean flag = true;
        
        log.info("---HeaderNames请求----->{}",request.getHeaderNames());
        log.info("---header请求----->{}",getHeadersInfo());


        String ip = request.getRemoteAddr();
        long startTime = System.currentTimeMillis();
        request.setAttribute("requestStartTime", startTime);
        HandlerMethod handlerMethod = (HandlerMethod) handler;
        Method method = handlerMethod.getMethod();
        log.info("[车护宝]用户:" + ip + ",访问目标:" + method.getDeclaringClass().getName() + "." + method.getName());
        // ..........接口放行（注册、登录）
        String uri = request.getRequestURI().trim().replaceAll("/{2,10}", "/");
        
        // 如果有NoSign注解就直接放行
        /*if (handlerMethod.getMethodAnnotation(NoSign.class) != null) {
            return true;
        }*/

        //放行登录注册；全部放行加上： || uri.contains("/api/") || uri.contains("/error")
        // 获取项目当前启动环境
        String profile = env.getProperty("spring.profiles.active");
        log.info("-------MyInterceptor--Spring Boot 【springboot】  使用profile为:{}" , profile);
        
        // 如果是开发环境，则放行所有接口：dev
        if("dev".equals(profile) || Constant.UN_VERIFY_URIS.contains(uri)){
        	log.info("uri 放行：{}", uri);
        	return flag;
        }
        
        MyHttpServletRequestWrapper myWrapper = new MyHttpServletRequestWrapper(request);
        String jsonStr = GetRequestJsonUtils.getRequestJsonString(myWrapper);
        BufferedReader reader = myWrapper.getReader();
        String str = null, dataStr = "";
        while ((str = reader.readLine()) != null) {
            dataStr += str;
        }
        //JSONObject jsonObject = JSONObject.parseObject(jsonStr);
        Map<String,Object> jsonMap = JSONObject.parseObject(jsonStr);
        // ..........对比登录用户的 token

        Integer userId = null;
        if (StringUtils.isNotBlank((String) jsonMap.get("userId"))) {
            userId = Integer.valueOf((String) jsonMap.get("userId"));
        }
        if (userId == null) {
            throw new BusinessException(ErrorCode.PARAMETER_NOT_EXIST.getCode(), "userId:登录用户ID不能为空");
        }
        String loginToken = "";
        try {
        	// 从db中获取用户的loginToken
        	/*ChbUserLogin userLogin = chbUserService.userToken(userId);
        	if(userLogin != null){
        		loginToken = userLogin.getLoginToken();
        	}*/
        } catch (Exception e) {
        	log.error(e.getMessage());
            throw new BusinessException(ErrorCode.FORCED_OUT.getCode(), "loginToken获取失败");
        }
        // token不存在则用户未登录账号
        if (StringUtils.isBlank(loginToken)) {
            throw new BusinessException(ErrorCode.FORCED_OUT.getCode(), "用户未登录");
        }

        // .......... 参数加密验证
        String sign = request.getParameter("sign");
        Enumeration<?> pNames = myWrapper.getParameterNames();
        Map<String, String> params = new TreeMap<String, String>();
        while (pNames.hasMoreElements()) {
            String pName = (String) pNames.nextElement();
            if ("sign".equals(pName)) continue;
            String pValue = request.getParameter(pName);
            params.put(pName, pValue);
        }
        StringBuffer sb = new StringBuffer("data[" + dataStr + "];");
        sb.append("sid[" + loginToken + "];");
        params.forEach((k, v) -> {
            sb.append(k).append("[").append(v).append("];");
        });
        log.info(sb.toString());
        String md5Sb = MD5Utils.format(sb.toString());
        log.info("加密签名字符串：{} ------ 请求签名字符串（sign）：{}", md5Sb, sign);
        if (!md5Sb.equals(sign)) {
        	// 状态码：999(强制退出)
        	// 该账号已在其他设备登录
            throw new BusinessException(ErrorCode.FORCED_OUT.getCode(), "登录异常");
        }
        return flag;
    }

    @Override
    public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {
        HandlerMethod handlerMethod = (HandlerMethod) handler;
        Method method = handlerMethod.getMethod();
        long startTime = (Long) request.getAttribute("requestStartTime");
        long endTime = System.currentTimeMillis();
        long executeTime = endTime - startTime;
        // 打印方法执行时间
        if (executeTime > 1000) {
            log.info("[" + method.getDeclaringClass().getName() + "." + method.getName() + "] 执行耗时 : "
                    + executeTime + "ms");
        } else {
        	log.info("[" + method.getDeclaringClass().getSimpleName() + "." + method.getName() + "] 执行耗时 : "
                    + executeTime + "ms");
        }
    }

    @Override
    public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {

    }
    
	/**
	 * @MethodName:getHeadersInfo
	 * @Author JuoChiu
	 * @Date 2017年11月6日 下午1:44:54
	 * @Description:获取header中的请求参数
	 * @return
	 * @ReturnType Map<String,String>
	 */
	@SuppressWarnings("rawtypes")
	private Map<String, String> getHeadersInfo() {
		Map<String, String> map = new HashMap<>();
		Enumeration headerNames = request.getHeaderNames();

		while (headerNames.hasMoreElements()) {
			String key = (String) headerNames.nextElement();

			String value = request.getHeader(key);

			map.put(key, value);
		}
		return map;
	}

}
